package net.wofly.sale.order.flow;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import net.wofly.flow.dto.FormPropertyDto;
import net.wofly.flow.service.IWorkFlowService;
import net.wofly.framework.util.ResultCode;
import net.wofly.framework.util.ReturnBean;
import net.wofly.right.domain.User;
import net.wofly.right.service.IUserService;
import net.wofly.sale.order.domain.Order;
import net.wofly.sale.order.domain.PayInfo;
import net.wofly.sale.order.domain.TakeGoodsShopInfo;
import net.wofly.sale.order.service.IPayInfoService;
import net.wofly.sale.order.service.ISaleOrderService;
import net.wofly.sale.order.service.ITakeGoodsShopInfoService;
import net.wofly.sale.order.util.NoMoneyOrderStatus;
import net.wofly.sale.order.util.OrderStatus;
import net.wofly.sale.order.util.OrderType;

@Service
public class OrderFlowServiceImpl implements IOrderFlowService {
	public static final String processDefKey = "pickinglist" ;
	
	@Autowired
	IWorkFlowService iWorkFlowService ;
	@Autowired
	ISaleOrderService iSaleOrderService ;
	@Autowired
	IPayInfoService iPayInfoService ;
	@Autowired
	ProcessEngine processEngine ;
	@Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    FormService formService ;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private IdentityService identityService;
    @Autowired
    private IUserService iUserService ;
    @Autowired
    private ITakeGoodsShopInfoService iTakeGoodsShopInfoService ;
	
    /**
     * 启动工作流时，下一步自动执行时，有些流程是需要传递 flow_opt 以决定工作流走向。自动执行的节点默认设置让工作流正常执行的值进行通过值 
     * flow_opt  当发起人后面是决策节点时，需要传递一个 flow_opt 值工作流来决定下一步工作流走向
     * 
     */
	@Override
	public ReturnBean<String> startWorkflow(String userID, String orderID ,String orderStatus ,Map<String, Object> variables) {
		long l = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(orderID).count() ;
		if (l>0) {
			return new ReturnBean<>(672 , "当前订单:'"+ orderID +"'己提交工作流，不可重复提交。");
		} 
		Order order = iSaleOrderService.findOne(orderID) ;
		if (order==null) {
			return new ReturnBean<>(611,"业务工作流实例不存在") ;
		}
		
		/*PayInfo payInfo = iPayInfoService.findByOrderIDOrderByPayTimeDesc(order.getOrderID()) ;
		
		if (null == payInfo) {
			return new ReturnBean<>(673 , "当前订单:'"+ orderID +"' 未支付，请支付后提交工作流。");
		}
		
		Integer payType = payInfo.getPayType() ;
		
		if (null == payType) {
			return new ReturnBean<>(674 , "当前订单:'"+ orderID +"' 支付类型不正常，请联系管理员详查。");
		}
		
		if (null == variables) {
			variables = new HashMap<>(); 
		}*/
		
		Integer orderType = order.getOrderType() ;
		String processDefKey = "" ;
		String flow_opt = orderStatus ;
		
        // 用来设置启动流程的人员ID，引擎会自动把用户ID保存到activiti:initiator中
        identityService.setAuthenticatedUserId(userID);
        
        if (orderType.equals(OrderType.会员订单.getValue())) { 	//会员
        		processDefKey = "order1" ;
        }else if(orderType.equals(OrderType.团购订单.getValue())) { //团购
        		processDefKey = "order7" ;
        }else if (orderType.equals(OrderType.酒店订单.getValue()) || orderType.equals(OrderType.流通订单.getValue()) || orderType.equals(OrderType.签单订单.getValue())) {	//酒店\流通\签单
        		processDefKey = "order3" ;
        }else if (orderType.equals(OrderType.订货会流通订单.getValue()) || orderType.equals(OrderType.订货会酒店订单.getValue())) {	//订货会
	    		processDefKey = "order7" ;
	    }else if (orderType.equals(OrderType.还货订单.getValue())) {	//还货
	    		processDefKey = "order9" ;
	    }else if (orderType.equals(OrderType.无款订单.getValue())) {	//内欠
	    		processDefKey = "order10" ;
	    		flow_opt = "1101" ;
	    }else if (orderType.equals(OrderType.宴会订单.getValue())) {	//宴会
	    		processDefKey = "order7" ;
	    }
        
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefKey, orderID, variables) ;
        
        if (null==processInstance) {
        		return new ReturnBean<>(673,"工作流启动出错！") ; 
        }
        
        /**
         * 流程启动后，下一个节点是发起人节点时，流程启动设置为任务的执行人，同时自动执行此任务
         */
        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult();
        
        if (task!=null) {
        		
        		allocationTaskCandicate( task , userID , order) ;
        		
	        	if (task.getName().equals("流程发起人")) {
	        		Map<String ,Object> mapFlow = new HashMap<>() ;
	        		if (!StringUtils.isEmpty(flow_opt)) {
	        			mapFlow.put("flow_opt", flow_opt) ;
	        		}
	        		
	        		taskService.complete(task.getId() , mapFlow);
	        		task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult();
	        		allocationTaskCandicate( task , userID , order) ;
	        }
        }
        
        order.setProcessDefKey(processDefKey);
        order.setProcessInsID(processInstance.getId());
        order.setStatus(Integer.valueOf(flow_opt));
        order.setTaskID(task.getId());
        order.setTaskName(task.getName());
        order.setTaskAssignee(task.getAssignee());
        
        iSaleOrderService.save(order) ;
        
        return new ReturnBean<>(0,"工作流启动成功" ,processInstance.getProcessInstanceId()) ; 
	}
	
	/**
	 * 为任务分配执行人
	 * 
	 * #startUser 工作流发起人 发起工作流用户
	 * 
	 * #clerk 店员候选人 会员自助下单时，需要将订单分配给其所选择的店面里的店员，再由店员签收任务
	 * 
	 * #followUser  流通或酒店客户下单时，需要将订单分配给客户对应的维护人，其直接为节点执行人
	 * 
	 * 
	 * @param task
	 * @param userID
	 */
	private void allocationTaskCandicate(Task task ,String startUserID ,Order order) {
		Integer placeOrderType = order.getPlaceOrderType() ;	
		String taskAssignee = task.getAssignee() ;
		
		if  (StringUtils.isEmpty(taskAssignee)) {
			return  ;
		}
		
		switch (taskAssignee) {
		case "#startUser" :
			processEngine.getTaskService().setAssignee(task.getId(), startUserID);
			break ;
		case "#clerk" :  
			if (placeOrderType==1) {  //只在会员客户自助下单时，根据选择的店面，将任务分配给店面里店员
				TakeGoodsShopInfo takeGoodsShopInfo = iTakeGoodsShopInfoService.findByOrderID(order.getOrderID());
				List<User> users = getClerkByShopID(takeGoodsShopInfo.getShopOrgID()) ;
				for(User u:users) {
					processEngine.getTaskService().addCandidateUser(task.getId(), u.getUserID()) ; 
				}
			}else {
				processEngine.getTaskService().setAssignee(task.getId(), order.getBuyer() );
			}
			break ;
		case "#followUser":
			if (placeOrderType==1) {  //只在流通或酒店客户自助下单时，将任务分配给客户给维护业务经理。由业务经理确认收款
				String placeOrderUserID = order.getBuyer() ;
				String followUserID = getSaleByCustomer(placeOrderUserID) ;
				processEngine.getTaskService().setAssignee(task.getId(), followUserID);
			}else {  //代客下单时，将任务分配给自己，由自己确认收款
				processEngine.getTaskService().setAssignee(task.getId(), order.getBuyer() );
			}
			break ;
		default :
			
		}
	}

	@Override
	public List<Order> findToDoList(String userID) {
		List<String> processDefKeys = new ArrayList<>() ;
		for(Integer i=1;i<11;i++) {
			processDefKeys.add("order" + i.toString()) ;
		}
		
		List<Task> tasks = new ArrayList<>();
		List<Task> todoList = new ArrayList<>();
		List<Task> unsignedTasks = new ArrayList<>();
		
		// 根据当前人的ID查询
		todoList = taskService.createTaskQuery().processDefinitionKeyIn(processDefKeys).taskAssignee(userID).orderByTaskCreateTime().desc().list();
		tasks.addAll(todoList) ;
		// 根据当前人未签收的任务
		unsignedTasks = taskService.createTaskQuery().processDefinitionKeyIn(processDefKeys).taskCandidateUser(userID).orderByTaskCreateTime().desc().list();
		tasks.addAll(unsignedTasks) ;
		
		if(tasks.isEmpty()) {
			return null ;
		}
		
		List<String> processInsIDs = new ArrayList<>() ;
        
        // 根据流程的业务ID查询实体并关联
        for (Task task : tasks) {
        		processInsIDs.add(task.getProcessInstanceId());
        }
        
        List<Order> orders = iSaleOrderService.findByInProcessInsID(processInsIDs) ;
        
        Collections.sort(orders, new Comparator<Order>() {
        		public int compare(Order arg0, Order arg1) {  
                return arg0.getOrderNo().compareTo(arg1.getOrderNo());  
            } 
        });
        
        Collections.reverse(orders);
        
        //TODO 获取任务中相关信息
        
        return orders ;
	}

	@Override
	public ReturnBean<String> complete(String userID, String taskID, String comment ,Map<String, String[]> mapRequest) {
		
		Task task = taskService.createTaskQuery().taskId(taskID).singleResult();
		
		if (null==task) {
			return new ReturnBean<>(610,"没有此任务或任务己执行完成！") ;
		}
		
		if (!StringUtils.equals(task.getAssignee(), userID)) {
			return new ReturnBean<>(603,"指定任务的办理人非当前用户，不能完成任务！") ;
		}
		
		List<FormPropertyDto>  fpds = iWorkFlowService.taskFormProperty( task) ;
		
		ReturnBean<Map<String ,Object>> rb = iWorkFlowService.getFlowVarMap(fpds , mapRequest) ;
		if(!rb.getCode().equals(ResultCode.SUCCESS)) {
			return new ReturnBean<>(rb.getCode(),rb.getMsg()) ;
		}
		
		Map<String ,Object> mapFlow = rb.getResult();
		
		String businessStatus = iWorkFlowService.getBsuinessStatus(mapFlow) ;
		
		iWorkFlowService.addComment( task ,mapFlow ) ;
		Order order = iSaleOrderService.findByProcessInsID(task.getProcessInstanceId());
		
		//白条订单， 完全回款后，发放赠品
		if (businessStatus.equals(OrderStatus.业务经理发放赠品.getValue().toString())) {
			ReturnBean<String> rtn = iSaleOrderService.decreaseStockForBaiTiaoOrder(order.getOrderID()) ;
			if(!rtn.getCode().equals(ReturnBean.CODE_SUCCESS)) {
				return rtn ;
			}
		}
		
		//无款订单，老板审核通过后，减库存
		if (order.getOrderType().equals(OrderType.无款订单.getValue()) && businessStatus.equals(NoMoneyOrderStatus.老板审核通过.getValue().toString()) ) {
			ReturnBean<Order> rtn = iSaleOrderService.decreaseStockForNoMoneyOrder(order.getOrderID()) ;
			if(!rtn.getCode().equals(ReturnBean.CODE_SUCCESS)) {
				return new ReturnBean<>(rtn.getCode(),rtn.getMsg()) ; 
			}
		}
		
//		PayInfo payInfo = iPayInfoService.findByOrderIDOrderByPayTimeDesc(order.getOrderID()) ;
		
		taskService.complete(taskID, mapFlow);
		
		// 完成任务后，判断下个节点是否为流程发起人节点， 如果为流程发起人节点且没有作务代理人时，系统将上次代理人设置到任务节点上
		Task nextTask = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
        if (nextTask!=null) {
        		if (nextTask.getAssignee().equals("#startUser") || nextTask.getAssignee().equals("#clerk") || nextTask.getAssignee().equals("#followUser")) {
        			processEngine.getTaskService().setAssignee(nextTask.getId(), iWorkFlowService.getHisAssignee(nextTask.getProcessInstanceId() ,nextTask));
        		}
//	        	if (nextTask.getName().equals("流程发起人")) {
//	        		processEngine.getTaskService().setAssignee(nextTask.getId(), iWorkFlowService.getInitiatorAssignee(nextTask.getProcessInstanceId()));
//	        }
        }
        
		//TODO 处理没有为任务指定执行人的节点，指定执行人，包括流程发起人
		
		
		order.setStatus(Integer.valueOf(businessStatus));
		if (null != nextTask) {
			order.setTaskID(nextTask.getId());
			order.setTaskName(nextTask.getName());
			order.setTaskAssignee(nextTask.getAssignee());
	    }else {
	    		order.setTaskID("");
			order.setTaskName("");
			order.setTaskAssignee("");
	    }
		
		iSaleOrderService.save(order) ;
		
		return new ReturnBean<>(0, "工作流执行完成" ) ;
	}

	@Override
	public ReturnBean<Order> getOrderForFlow(String orderID) {
		Order order = iSaleOrderService.findOne(orderID) ;
		
		if (order==null) {
			return new ReturnBean<>(611,"业务工作流实例不存在") ;
		}
		
		if (order.getTaskID() == null) {
			return new ReturnBean<>(612,"业务工作流任务不存在") ;
		}
		
		Task task = taskService.createTaskQuery().taskId(order.getTaskID()).singleResult();
		
		if (null == task) {
			return new ReturnBean<>(0,"获取成功" ,order ) ; 
		}
		
		List<FormPropertyDto> formPropertyDtos = iWorkFlowService.taskFormProperty( task) ;
		
		List<Comment> comments =  taskService.getProcessInstanceComments(order.getProcessInsID()) ;
		order.setComments(comments);
		order.setFormPropertyDtos(formPropertyDtos);
		
		return new ReturnBean<>(0, "获取工作流信息成功" , order) ;
	}
	
	/**
	 * 酒店或流通客户自助下单时，通过客户ID查找客户的维护人（维护业务经理）用户ID
	 * 并将订单分配给维护人
	 * 
	 * @param customUserID
	 * @return
	 */
	private String getSaleByCustomer(String customUserID){
		String followUserID = iUserService.findFollowUserByCustomer(customUserID) ;
		return followUserID ;
	}
	
	/**
	 * 会员客户自助下单时，通过客户所选的店面，找到店面的所有店员，
	 * 并将订单分配给店员，再由店员主动签收任务。并执行任务
	 * 
	 * @param shopID（originationID 店面组织机构ID）   
	 * @return
	 */
	private List<User> getClerkByShopID(String shopID){
		List<User> users = iUserService.findByOrganizationID(shopID) ;
		
		return users ;
	}

	@Override
	public ReturnBean<String> claimTask(String userID, String taskID) {
		taskService.claim(taskID, userID);
		return new ReturnBean<>(0, "任务签收成功！") ;
	}

	@Override
	public ReturnBean<String> unclaimTask(String userID, String taskID) {
		
		taskService.unclaim(taskID);
		return new ReturnBean<>(0, "任务反签收成功！") ;
	}

	@Override
	public Order getOrderForFlow(Order order) {
		
		Task task = taskService.createTaskQuery().taskId(order.getTaskID()).singleResult();
		
		if (null == task) {
			return null; 
		}
		
		List<FormPropertyDto> formPropertyDtos = iWorkFlowService.taskFormProperty(task) ;
		
		List<Comment> comments =  taskService.getProcessInstanceComments(order.getProcessInsID()) ;
		order.setComments(comments);
		order.setFormPropertyDtos(formPropertyDtos);
		
		return order ;
	}
	
}
